package znet

import (
	"context"
	"errors"
	"fmt"
	"net/url"
	"sync"
	"sync/atomic"
	"time"

	"gitee.com/chen_wei_jing/kinx/zconf"
	"gitee.com/chen_wei_jing/kinx/zdecoder"
	"gitee.com/chen_wei_jing/kinx/ziface"
	"gitee.com/chen_wei_jing/kinx/zlog"
	"gitee.com/chen_wei_jing/kinx/zpack"
	"github.com/xtaci/kcp-go/v5"
)

type KcpClient struct {
	// IP of the target server to connect 目标连接服务器的IP
	Ip string

	// Port of the target server to connect 目标连接服务器的端口
	Port int
	Url  *url.URL // 扩展，连接时带上其他参数

	// Connection instance 连接实例的锁，保证可见性
	connMux sync.Mutex

	// Hook function called on connection start 该client的连接创建时Hook函数
	onConnStart func(conn ziface.IConnection)

	// Hook function called on connection stop 该client的连接断开时的Hook函数
	onConnStop func(conn ziface.IConnection)

	// Data packet packer 数据报文封包方式
	packet ziface.IDataPack
	// Asynchronous channel for capturing connection close status 异步捕获连接关闭状态

	exitChan chan struct{}
	// Message management module 消息管理模块

	msgHandler ziface.IMsgHandle
	// Disassembly and assembly decoder for resolving sticky and broken packages

	//断粘包解码器
	decoder ziface.IDecoder
	// Heartbeat checker 心跳检测器

	hc ziface.IHeartbeatChecker
	// Use TLS 使用TLS
	useTLS bool

	// Error channel
	ErrChan chan error

	connMrg ziface.IConnManager

	// connection id
	cID uint64
}

func (k *KcpClient) AddRouter(msgID uint32, router ziface.IRouter) {
	k.msgHandler.AddRouter(msgID, router)
}

func (k *KcpClient) SetOnConnStart(hookFunc func(ziface.IConnection)) {
	k.onConnStart = hookFunc
}

func (k *KcpClient) SetOnConnStop(hookFunc func(ziface.IConnection)) {
	k.onConnStop = hookFunc
}

func (k *KcpClient) GetOnConnStart() func(ziface.IConnection) {
	return k.onConnStart
}

func (k *KcpClient) GetOnConnStop() func(ziface.IConnection) {
	return k.onConnStop
}

func (k *KcpClient) GetPacket() ziface.IDataPack {
	return k.packet
}

func (k *KcpClient) SetPacket(packet ziface.IDataPack) {
	k.packet = packet
}

func (k *KcpClient) GetMsgHandler() ziface.IMsgHandle {
	return k.msgHandler
}

func (k *KcpClient) StartHeartBeat(interval time.Duration) {
	checker := NewHeartbeatChecker(interval, false)

	// Add the heartbeat checker's route to the client's message handler.
	// (添加心跳检测的路由)
	k.AddRouter(checker.MsgID(), checker.Router())

	// Bind the heartbeat checker to the client's connection.
	// (client绑定心跳检测器)
	k.hc = checker
}

func (k *KcpClient) AddInterceptor(interceptor ziface.IInterceptor) {
	k.msgHandler.AddInterceptor(interceptor)
}

func (k *KcpClient) SetDecoder(decoder ziface.IDecoder) {
	k.decoder = decoder
}

func (k *KcpClient) GetLengthField() *ziface.LengthField {
	if k.decoder != nil {
		return k.decoder.GetLengthField()
	}
	return nil
}

func (k *KcpClient) GetErrChan() chan error {
	return k.ErrChan
}

func (k *KcpClient) Connect(timeout int) (connId uint64, err error) {
	timer := time.NewTimer(time.Duration(timeout) * time.Second)
	succ := make(chan bool, 1)
	result := false
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	zlog.Ins().DebugF("Connect Kcp Server %s:%d", k.Ip, k.Port)

	// 建立连接生成kcp包
	conn, err := kcp.DialWithOptions(fmt.Sprintf("%s:%d", k.Ip, k.Port), nil, 10, 3)
	if err != nil {
		zlog.Ins().ErrorF("client start err, exit!")
		return 0, errors.New("connect failed")
	}

	conn.SetACKNoDelay(false)
	conn.SetNoDelay(1, 10, 2, 1)
	conn.SetWindowSize(32, 32)

	// 2. 设置超时（关键：避免无限等待）
	// conn.SetReadDeadline(time.Now().Add(10 * time.Second))
	// conn.SetWriteDeadline(time.Now().Add(2 * time.Second))

	go func() {
		select {
		case <-ctx.Done():
			succ <- false
			fmt.Println("退出协程")
			return
		default:
			readBuf := make([]byte, 1024)
			n, err := conn.Read(readBuf)

			zlog.Ins().DebugF("err:%v", err)

			if n > 0 && err == nil {
				succ <- true
			} else {
				succ <- false
			}
		}
	}()

	time.Sleep(200 * time.Millisecond)

	dp := zpack.Factory().NewPack(ziface.ZinxDataPack)
	hello, _ := dp.Pack(zpack.NewMsgPackage(ziface.HeartBeatDefaultMsgID, []byte("Client Heartbeat!")))

	// 3. 发送测试包（验证对端可达）
	if _, err := conn.Write(hello); err != nil {
		conn.Close()
		return 0, fmt.Errorf("send ping failed: %w", err)
	}

	select {
	case <-timer.C:
		conn.Close()
		result = false
	case result = <-succ:
	}

	zlog.Ins().InfoF("[client] 连接服务器 %s:%d 结果:%t", k.Ip, k.Port, result)

	if !result {
		return 0, errors.New("connect err!")
	}

	// 生成client id
	newCid := atomic.AddUint64(&k.cID, 1)

	// 生成 kcp conn
	kcpConn := newKcpClientConn(k, conn, newCid)

	k.connMrg.Add(kcpConn)

	// go newKcpClientConn()
	go k.StartConn(kcpConn)

	// 加入到管理器中
	return newCid, nil
}

func (k *KcpClient) Connect2() (*kcp.UDPSession, error) {

	// 1. 拨号创建KCP连接（底层UDP）
	// Dial参数：地址、密码（可选）、数据分片大小、窗口大小
	conn, err := kcp.DialWithOptions(fmt.Sprintf("%s:%d", k.Ip, k.Port), nil, 10, 3)
	if err != nil {
		return nil, fmt.Errorf("dial kcp failed: %w", err)
	}

	// 2. 设置超时（关键：避免无限等待）
	conn.SetReadDeadline(time.Now().Add(5 * time.Second))
	conn.SetWriteDeadline(time.Now().Add(2 * time.Second))

	dp := zpack.Factory().NewPack(ziface.ZinxDataPack)
	hello, _ := dp.Pack(zpack.NewMsgPackage(6666, []byte("Client Heartbeat!")))

	// 3. 发送测试包（验证对端可达）
	if _, err := conn.Write(hello); err != nil {
		conn.Close()
		return nil, fmt.Errorf("send ping failed: %w", err)
	}

	// 4. 等待对端响应（确认KCP连接生效）
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil || n <= 0 {
		conn.Close()
		return nil, fmt.Errorf("read pong failed: %w", err)
	}

	// 6. 恢复读写超时（业务层按需调整）
	conn.SetReadDeadline(time.Time{})
	conn.SetWriteDeadline(time.Time{})

	fmt.Println("KCP连接成功（客户端）")
	return conn, nil
}

// 发送数据
func (k *KcpClient) SendMsg(connId uint64, msgId uint32, data []byte) error {
	if k.connMrg == nil {
		zlog.Ins().ErrorF("Send Err, connId:%d msgId:%d", connId, msgId)
		return errors.New("No conn Mrg")
	}

	conn, err := k.connMrg.Get(connId)

	if err != nil {
		zlog.Ins().ErrorF("Send Err, connId:%d msgId:%d err:%s", connId, msgId, err)
		return err
	}

	err = conn.SendMsg(msgId, data)
	if err != nil {
		zlog.Ins().ErrorF("Send Err, connId:%d msgId:%d", connId, msgId)
		return err
	}
	return err
}

func (k *KcpClient) StartConn(conn ziface.IConnection) {
	// HeartBeat check
	if k.hc != nil {
		// Clone a heart-beat checker from the server side
		heartBeatChecker := k.hc.Clone()

		// Bind current connection
		heartBeatChecker.BindConn(conn)
	}

	// Start processing business for the current connection
	conn.Start()
}

func (k *KcpClient) Close(connId uint64) {
	if k.connMrg == nil {
		zlog.Ins().ErrorF("Close Err, connId:%d", connId)
		return
	}

	conn, err := k.connMrg.Get(connId)

	if err != nil {
		zlog.Ins().ErrorF("Close Err, connId:%d", connId)
		return
	}

	if conn != nil {
		conn.Stop()
	}
}

func NewKcpClient(ip string, port int, heartbeatMax int) ziface.IKcpClient {
	zconf.GlobalObject.HeartbeatMax = heartbeatMax
	kc := &KcpClient{
		Ip:         ip,
		Port:       port,
		exitChan:   make(chan struct{}),
		msgHandler: newCliMsgHandle(),
		//断粘包解码器
		packet:  zpack.Factory().NewPack(ziface.ZinxDataPack),
		decoder: zdecoder.NewTLVDecoder(), // Default to using TLV decode (默认使用TLV的解码方式)
		// Heartbeat checker 心跳检测器
		useTLS: true,
		// Error channel
		ErrChan: nil,
		connMrg: newConnManager(),
		// connection id
		cID: 100,
	}

	// (将解码器添加到拦截器最前面)
	if kc.decoder != nil {
		kc.msgHandler.SetHeadInterceptor(kc.decoder)
	}

	// Start worker pool mechanism
	// (启动worker工作池机制)
	// kc.msgHandler.StartWorkerPool()

	return kc
}

// cat /proc/154179/limits | grep "Max open files"
// ls -l /proc/154179/fd | wc -l
